#include "URBSerializer.h"

ULONG URBSerializer::SerializeUrbHeader(_URB_HEADER *pHdr)
{
    ULONG bytesWrote = 0;
    ULONG uDeviceHandle = (ULONG) pHdr->UsbdDeviceHandle;
    bytesWrote += buffer.Write(&pHdr->Length,    sizeof(pHdr->Length));
    bytesWrote += buffer.Write(&pHdr->Function,  sizeof(pHdr->Function));
    bytesWrote += buffer.Write(&pHdr->Status,    sizeof(pHdr->Status));
    bytesWrote += buffer.Write(&uDeviceHandle,   sizeof(uDeviceHandle));
    bytesWrote += buffer.Write(&pHdr->UsbdFlags, sizeof(pHdr->UsbdFlags));

    return bytesWrote;
}

ULONG URBSerializer::SerializeTransferBuffer(ULONG length, PVOID pBuffer, PMDL pMDL)
{
    ULONG bytesWrote = 0;
    bool thereIsAnMDL = (pBuffer == NULL) ? TRUE : FALSE;
    // Ignore MDL if both TransferBufferMDL and TransferBuffer are specified

    bytesWrote += buffer.Write(thereIsAnMDL);
    bytesWrote += buffer.Write(&length, sizeof(length));
	//KdPrint(("TransferBufferLength = 0x%x", length));
    if (thereIsAnMDL)
    {
		if (pMDL == NULL)
		{
			// There's neither TransferBuffer nor TransferBufferMDL
			return NULL;
		}
        PVOID pBufferMDL = (PVOID) MmGetSystemAddressForMdlSafe(pMDL, NormalPagePriority);
        if (pBufferMDL == NULL)
        {
            KdPrint(("URBSerializer::SerializeTransferBuffer: Failed to map MDL\n"));
            return NULL;
        }
        bytesWrote += buffer.Write(pBufferMDL, length);
        return bytesWrote;
    }

    bytesWrote += buffer.Write(pBuffer, length);
    return bytesWrote;
}

ULONG URBSerializer::SerializeURB(PURB pUrb, PVOID pBuffer, ULONG bufferSize, BOOLEAN isCompleted)
{
    ULONG bytesWrote = 0;
    USHORT i, j;
    ULONG uHandle;

    if (pUrb == NULL)
    {
        KdPrint(("URBSerializer::SerializeURB(...): pUrb == NULL\n"));
        return NULL;
    }
    
    switch (pUrb->UrbHeader.Function)
    {
    case URB_FUNCTION_SELECT_CONFIGURATION:
        {
            _URB_SELECT_CONFIGURATION *pSC = (_URB_SELECT_CONFIGURATION *) pUrb;
            PUSBD_INTERFACE_INFORMATION pInterface = &pSC->Interface;

            buffer.SetBuffer(pBuffer, bufferSize);
            bytesWrote += buffer.Write((UCHAR)PACK_URB_SELECT_CONFIGURATION);
            bytesWrote += SerializeUrbHeader(&pSC->Hdr);
            bytesWrote += buffer.Write(isCompleted);

            bool bConfigurationDescriptor = (pSC->ConfigurationDescriptor != NULL) ? TRUE : FALSE;
            bytesWrote += buffer.Write(bConfigurationDescriptor);
            if(!bConfigurationDescriptor)
            {
                uHandle = (ULONG) pSC->ConfigurationHandle;
                bytesWrote += buffer.Write(&uHandle, sizeof(uHandle));
                break;
            }

            PUSB_CONFIGURATION_DESCRIPTOR pConfD = pSC->ConfigurationDescriptor;
            bytesWrote += buffer.Write(&pConfD->bLength,             sizeof(pConfD->bLength));
            bytesWrote += buffer.Write(&pConfD->bDescriptorType,     sizeof(pConfD->bDescriptorType));
            bytesWrote += buffer.Write(&pConfD->wTotalLength,        sizeof(pConfD->wTotalLength));
            bytesWrote += buffer.Write(&pConfD->bNumInterfaces,      sizeof(pConfD->bNumInterfaces));
            bytesWrote += buffer.Write(&pConfD->bConfigurationValue, sizeof(pConfD->bConfigurationValue));
            bytesWrote += buffer.Write(&pConfD->iConfiguration,      sizeof(pConfD->iConfiguration));
            bytesWrote += buffer.Write(&pConfD->bmAttributes,        sizeof(pConfD->bmAttributes));
            bytesWrote += buffer.Write(&pConfD->MaxPower,            sizeof(pConfD->MaxPower));
            
            for (i=0; i<pConfD->bNumInterfaces; ++i)
            {
                bytesWrote += buffer.Write(&pInterface[i].Length,           sizeof(pInterface[i].Length));
                bytesWrote += buffer.Write(&pInterface[i].InterfaceNumber,  sizeof(pInterface[i].InterfaceNumber));
                bytesWrote += buffer.Write(&pInterface[i].AlternateSetting, sizeof(pInterface[i].AlternateSetting));
                bytesWrote += buffer.Write(&pInterface[i].Class,            sizeof(pInterface[i].Class));
                bytesWrote += buffer.Write(&pInterface[i].SubClass,         sizeof(pInterface[i].SubClass));
                bytesWrote += buffer.Write(&pInterface[i].Protocol,         sizeof(pInterface[i].Protocol));

                uHandle = (ULONG) pInterface[i].InterfaceHandle;
                bytesWrote += buffer.Write(&uHandle, sizeof(uHandle));

                bytesWrote += buffer.Write(&pInterface[i].NumberOfPipes, sizeof(pInterface[i].NumberOfPipes));

                _USBD_PIPE_INFORMATION *Pipes = pInterface[i].Pipes;
                for (j=0; j<pInterface[i].NumberOfPipes; ++j)
                {
                    bytesWrote += buffer.Write(&Pipes[j].MaximumPacketSize, sizeof(Pipes[j].MaximumPacketSize));
                    bytesWrote += buffer.Write(&Pipes[j].EndpointAddress,   sizeof(Pipes[j].EndpointAddress));
                    bytesWrote += buffer.Write(&Pipes[j].Interval,          sizeof(Pipes[j].Interval));
                    bytesWrote += buffer.Write(&Pipes[j].PipeType,          sizeof(Pipes[j].PipeType));

                    uHandle = (ULONG) Pipes[j].PipeHandle;
                    bytesWrote += buffer.Write(&uHandle, sizeof(uHandle));

                    bytesWrote += buffer.Write(&Pipes[j].MaximumTransferSize, sizeof(Pipes[j].MaximumTransferSize));
                    bytesWrote += buffer.Write(&Pipes[j].PipeFlags,           sizeof(Pipes[j].PipeFlags));
                }
            }
            bytesWrote += buffer.Write(&pSC->ConfigurationHandle, sizeof(pSC->ConfigurationHandle));
        }
        break;
        
    case URB_FUNCTION_SELECT_INTERFACE:
        {
            _URB_SELECT_INTERFACE *pSI = (_URB_SELECT_INTERFACE *) pUrb;

            buffer.SetBuffer(pBuffer, bufferSize);
            bytesWrote += buffer.Write((UCHAR)PACK_URB_SELECT_INTERFACE);
            bytesWrote += SerializeUrbHeader(&pSI->Hdr);
            bytesWrote += buffer.Write(isCompleted);

            uHandle = (ULONG) pSI->ConfigurationHandle;
            bytesWrote += buffer.Write(&uHandle, sizeof(uHandle));

            bytesWrote += buffer.Write(&pSI->Interface.Length,           sizeof(pSI->Interface.Length));
            bytesWrote += buffer.Write(&pSI->Interface.InterfaceNumber,  sizeof(pSI->Interface.InterfaceNumber));
            bytesWrote += buffer.Write(&pSI->Interface.AlternateSetting, sizeof(pSI->Interface.AlternateSetting));
            bytesWrote += buffer.Write(&pSI->Interface.Class,            sizeof(pSI->Interface.Class));
            bytesWrote += buffer.Write(&pSI->Interface.SubClass,         sizeof(pSI->Interface.SubClass));
            bytesWrote += buffer.Write(&pSI->Interface.Protocol,         sizeof(pSI->Interface.Protocol));

            uHandle = (ULONG) pSI->Interface.InterfaceHandle;
            bytesWrote += buffer.Write(&uHandle,	sizeof(uHandle));

            bytesWrote += buffer.Write(&pSI->Interface.NumberOfPipes, sizeof(pSI->Interface.NumberOfPipes));

            _USBD_PIPE_INFORMATION *Pipes = pSI->Interface.Pipes;
            for (i=0; i<pSI->Interface.NumberOfPipes; ++i)
            {
                bytesWrote += buffer.Write(&Pipes[i].MaximumPacketSize, sizeof(Pipes[i].MaximumPacketSize));
                bytesWrote += buffer.Write(&Pipes[i].EndpointAddress,   sizeof(Pipes[i].EndpointAddress));
                bytesWrote += buffer.Write(&Pipes[i].Interval,          sizeof(Pipes[i].Interval));
                bytesWrote += buffer.Write(&Pipes[i].PipeType,          sizeof(Pipes[i].PipeType));

                uHandle = (ULONG) Pipes[i].PipeHandle;
                bytesWrote += buffer.Write(&uHandle, sizeof(uHandle));

                bytesWrote += buffer.Write(&Pipes[i].MaximumTransferSize, sizeof(Pipes[i].MaximumTransferSize));
                bytesWrote += buffer.Write(&Pipes[i].PipeFlags,           sizeof(Pipes[i].PipeFlags));
            }
        }
        break;
        
    case URB_FUNCTION_ABORT_PIPE:
    // usb.h: #define URB_FUNCTION_RESET_PIPE URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL
    //case URB_FUNCTION_RESET_PIPE:
    case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL:
    case URB_FUNCTION_SYNC_RESET_PIPE:
    case URB_FUNCTION_SYNC_CLEAR_STALL:
        {
            _URB_PIPE_REQUEST *pPR = (_URB_PIPE_REQUEST *) pUrb;

            buffer.SetBuffer(pBuffer, bufferSize);
            bytesWrote += buffer.Write((UCHAR)PACK_URB_PIPE_REQUEST);
            bytesWrote += SerializeUrbHeader(&pPR->Hdr);
            bytesWrote += buffer.Write(isCompleted);

            uHandle = (ULONG) pPR->PipeHandle;
            bytesWrote += buffer.Write(&uHandle, sizeof(uHandle));		
        }
        break;
        
    case URB_FUNCTION_GET_CURRENT_FRAME_NUMBER:
        {
            _URB_GET_CURRENT_FRAME_NUMBER *pGCFN = (_URB_GET_CURRENT_FRAME_NUMBER *) pUrb;

            buffer.SetBuffer(pBuffer, bufferSize);
            bytesWrote += buffer.Write((UCHAR)PACK_URB_GET_CURRENT_FRAME_NUMBER);
            bytesWrote += SerializeUrbHeader(&pGCFN->Hdr);
            bytesWrote += buffer.Write(isCompleted);

            bytesWrote += buffer.Write(&pGCFN->FrameNumber, sizeof(pGCFN->FrameNumber));	 
        }
        break;
        
    case URB_FUNCTION_CONTROL_TRANSFER:
        {
            _URB_CONTROL_TRANSFER *pCT = (_URB_CONTROL_TRANSFER *) pUrb;

            buffer.SetBuffer(pBuffer, bufferSize);
            bytesWrote += buffer.Write((UCHAR)PACK_URB_CONTROL_TRANSFER);
            bytesWrote += SerializeUrbHeader(&pCT->Hdr);
            bytesWrote += buffer.Write(isCompleted);
            
            uHandle = (ULONG) pCT->PipeHandle;
            bytesWrote += buffer.Write(&uHandle, sizeof(uHandle));
            bytesWrote += buffer.Write(&pCT->TransferFlags,	sizeof(pCT->TransferFlags));

            BOOLEAN dataIsRequestedFromDevice = (BOOLEAN)(pCT->TransferFlags & USBD_TRANSFER_DIRECTION_IN);

            if(((!dataIsRequestedFromDevice) && (!isCompleted)) || (dataIsRequestedFromDevice && isCompleted))
            {
                bytesWrote += SerializeTransferBuffer(pCT->TransferBufferLength,
                    pCT->TransferBuffer, pCT->TransferBufferMDL);
            }

            bytesWrote += buffer.Write(pCT->SetupPacket, sizeof(pCT->SetupPacket));
        }
        break;
#if (_WIN32_WINNT >= 0x0600)
    case URB_FUNCTION_CONTROL_TRANSFER_EX:
        {
            _URB_CONTROL_TRANSFER_EX *pCTE = (_URB_CONTROL_TRANSFER_EX *) pUrb;

            buffer.SetBuffer(pBuffer, bufferSize);
            bytesWrote += buffer.Write((UCHAR)PACK_URB_CONTROL_TRANSFER_EX);
            bytesWrote += SerializeUrbHeader(&pCTE->Hdr);
            bytesWrote += buffer.Write(isCompleted);

            uHandle = (ULONG) pCTE->PipeHandle;
            bytesWrote += buffer.Write(&uHandle, sizeof(uHandle));
            bytesWrote += buffer.Write(&pCTE->TransferFlags,	sizeof(pCTE->TransferFlags));
            
            BOOLEAN dataIsRequestedFromDevice = (BOOLEAN)(pCTE->TransferFlags & USBD_TRANSFER_DIRECTION_IN);

            if(((!dataIsRequestedFromDevice) && (!isCompleted)) || (dataIsRequestedFromDevice && isCompleted))
            {
                bytesWrote += SerializeTransferBuffer(pCTE->TransferBufferLength,
                                                pCTE->TransferBuffer, pCTE->TransferBufferMDL);
            }
            
            bytesWrote += buffer.Write(&pCTE->Timeout,     sizeof(pCTE->Timeout));
            bytesWrote += buffer.Write(pCTE->SetupPacket, sizeof(pCTE->SetupPacket));
        }
        break;
#endif

    case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
        {
            _URB_BULK_OR_INTERRUPT_TRANSFER *pBIOT = (_URB_BULK_OR_INTERRUPT_TRANSFER *) pUrb;
            
            buffer.SetBuffer(pBuffer, bufferSize);
            bytesWrote += buffer.Write((UCHAR)PACK_URB_BULK_OR_INTERRUPT_TRANSFER);
            bytesWrote += SerializeUrbHeader(&pBIOT->Hdr);
            bytesWrote += buffer.Write(isCompleted);

            uHandle = (ULONG) pBIOT->PipeHandle;
            bytesWrote += buffer.Write(&uHandle, sizeof(uHandle));

            bytesWrote += buffer.Write(&pBIOT->TransferFlags, sizeof(pBIOT->TransferFlags));

            BOOLEAN dataIsRequestedFromDevice = (BOOLEAN)(pBIOT->TransferFlags & USBD_TRANSFER_DIRECTION_IN);

            if(((!dataIsRequestedFromDevice) && (!isCompleted)) || (dataIsRequestedFromDevice && isCompleted))
            {
                bytesWrote += SerializeTransferBuffer(pBIOT->TransferBufferLength,
                                            pBIOT->TransferBuffer, pBIOT->TransferBufferMDL);
            }
        }
        break;
        
    case URB_FUNCTION_ISOCH_TRANSFER:
        {
            _URB_ISOCH_TRANSFER *pIT = (_URB_ISOCH_TRANSFER *) pUrb;

            buffer.SetBuffer(pBuffer, bufferSize);
            bytesWrote += buffer.Write((UCHAR)PACK_URB_ISOCH_TRANSFER);
            bytesWrote += SerializeUrbHeader(&pIT->Hdr);
            bytesWrote += buffer.Write(isCompleted);

            uHandle = (ULONG) pIT->PipeHandle;
            bytesWrote += buffer.Write(&uHandle, sizeof(uHandle));

            bytesWrote += buffer.Write(&pIT->TransferFlags,	sizeof(pIT->TransferFlags));

            BOOLEAN dataIsRequestedFromDevice = (BOOLEAN)(pIT->TransferFlags & USBD_TRANSFER_DIRECTION_IN);
            
            if(((!dataIsRequestedFromDevice) && (!isCompleted)) || (dataIsRequestedFromDevice && isCompleted))
            {
                bytesWrote += SerializeTransferBuffer(pIT->TransferBufferLength,
                                                pIT->TransferBuffer, pIT->TransferBufferMDL);
            }

            bytesWrote += buffer.Write(&pIT->StartFrame,      sizeof(pIT->StartFrame));
            bytesWrote += buffer.Write(&pIT->NumberOfPackets, sizeof(pIT->NumberOfPackets));
            bytesWrote += buffer.Write(&pIT->ErrorCount,      sizeof(pIT->ErrorCount));

            PUSBD_ISO_PACKET_DESCRIPTOR IsoPacket = pIT->IsoPacket;
            for (i=0; i<pIT->NumberOfPackets; ++i)
            {
                bytesWrote += buffer.Write(&IsoPacket[i].Offset, sizeof(IsoPacket[i].Offset));
                bytesWrote += buffer.Write(&IsoPacket[i].Length, sizeof(IsoPacket[i].Length));
                bytesWrote += buffer.Write(&IsoPacket[i].Status, sizeof(IsoPacket[i].Status));
            }
        }
        break;
        
    case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
    case URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT:
    case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE:
	{
		_URB_CONTROL_DESCRIPTOR_REQUEST *pCDR = (_URB_CONTROL_DESCRIPTOR_REQUEST *) pUrb;

            buffer.SetBuffer(pBuffer, bufferSize);
            bytesWrote += buffer.Write((UCHAR)PACK_URB_CONTROL_DESCRIPTOR_REQUEST);
            bytesWrote += SerializeUrbHeader(&pCDR->Hdr);
            bytesWrote += buffer.Write(isCompleted);
			BOOLEAN thereIsBuffer = isCompleted ? TRUE : FALSE;
			bytesWrote += buffer.Write(thereIsBuffer);
			if (thereIsBuffer)
			{
				bytesWrote += SerializeTransferBuffer(pCDR->TransferBufferLength,
                                            pCDR->TransferBuffer, pCDR->TransferBufferMDL);
			}
            bytesWrote += buffer.Write(&pCDR->Index,          sizeof(pCDR->Index));
            bytesWrote += buffer.Write(&pCDR->DescriptorType, sizeof(pCDR->DescriptorType));
            bytesWrote += buffer.Write(&pCDR->LanguageId,     sizeof(pCDR->LanguageId));
	}
    case URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE:
    case URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT:		
    case URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE:
        {
            _URB_CONTROL_DESCRIPTOR_REQUEST *pCDR = (_URB_CONTROL_DESCRIPTOR_REQUEST *) pUrb;

            buffer.SetBuffer(pBuffer, bufferSize);
            bytesWrote += buffer.Write((UCHAR)PACK_URB_CONTROL_DESCRIPTOR_REQUEST);
            bytesWrote += SerializeUrbHeader(&pCDR->Hdr);
            bytesWrote += buffer.Write(isCompleted);
			BOOLEAN thereIsBuffer = isCompleted ? FALSE : TRUE;
			bytesWrote += buffer.Write(thereIsBuffer);
			if (thereIsBuffer)
			{				
				bytesWrote += SerializeTransferBuffer(pCDR->TransferBufferLength,
                                            pCDR->TransferBuffer, pCDR->TransferBufferMDL);
			}
            bytesWrote += buffer.Write(&pCDR->Index,          sizeof(pCDR->Index));
            bytesWrote += buffer.Write(&pCDR->DescriptorType, sizeof(pCDR->DescriptorType));
            bytesWrote += buffer.Write(&pCDR->LanguageId,     sizeof(pCDR->LanguageId));
        }
        break;
        
    case URB_FUNCTION_SET_FEATURE_TO_DEVICE:
    case URB_FUNCTION_SET_FEATURE_TO_INTERFACE:
    case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT:
    case URB_FUNCTION_SET_FEATURE_TO_OTHER:
    case URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE:
    case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE:
    case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT:
    case URB_FUNCTION_CLEAR_FEATURE_TO_OTHER:
        {
            _URB_CONTROL_FEATURE_REQUEST *pCFR = (_URB_CONTROL_FEATURE_REQUEST *) pUrb;

            buffer.SetBuffer(pBuffer, bufferSize);
            bytesWrote += buffer.Write((UCHAR)PACK_URB_CONTROL_FEATURE_REQUEST);
            bytesWrote += SerializeUrbHeader(&pCFR->Hdr);
            bytesWrote += buffer.Write(isCompleted);

            bytesWrote += buffer.Write(&pCFR->FeatureSelector, sizeof(pCFR->FeatureSelector));
            bytesWrote += buffer.Write(&pCFR->Index,           sizeof(pCFR->Index));
        }
        break;
        
    case URB_FUNCTION_GET_STATUS_FROM_DEVICE:
    case URB_FUNCTION_GET_STATUS_FROM_INTERFACE:
    case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT:
    case URB_FUNCTION_GET_STATUS_FROM_OTHER:
        {
            _URB_CONTROL_GET_STATUS_REQUEST *pCGSR = (_URB_CONTROL_GET_STATUS_REQUEST *) pUrb;

            buffer.SetBuffer(pBuffer, bufferSize);
            bytesWrote += buffer.Write((UCHAR)PACK_URB_CONTROL_GET_STATUS_REQUEST);
            bytesWrote += SerializeUrbHeader(&pCGSR->Hdr);
            bytesWrote += buffer.Write(isCompleted);

			if (isCompleted)
			{
				bytesWrote += SerializeTransferBuffer(pCGSR->TransferBufferLength,
                                        pCGSR->TransferBuffer, pCGSR->TransferBufferMDL);
			}
            bytesWrote += buffer.Write(&pCGSR->Index, sizeof(pCGSR->Index));
        }
        break;
        
    case URB_FUNCTION_VENDOR_DEVICE:
    case URB_FUNCTION_VENDOR_INTERFACE:
    case URB_FUNCTION_VENDOR_ENDPOINT:
    case URB_FUNCTION_VENDOR_OTHER:
    case URB_FUNCTION_CLASS_DEVICE:
    case URB_FUNCTION_CLASS_INTERFACE:
    case URB_FUNCTION_CLASS_ENDPOINT:
    case URB_FUNCTION_CLASS_OTHER:
        {
            _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *pCVOCR = (_URB_CONTROL_VENDOR_OR_CLASS_REQUEST *) pUrb;

            buffer.SetBuffer(pBuffer, bufferSize);
            bytesWrote += buffer.Write((UCHAR)PACK_URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
            bytesWrote += SerializeUrbHeader(&pCVOCR->Hdr);
            bytesWrote += buffer.Write(isCompleted);

            bytesWrote += buffer.Write(&pCVOCR->TransferFlags, sizeof(pCVOCR->TransferFlags));

            BOOLEAN dataIsRequestedFromDevice = (BOOLEAN)(pCVOCR->TransferFlags & USBD_TRANSFER_DIRECTION_IN);

            if(((!dataIsRequestedFromDevice) && (!isCompleted)) || (dataIsRequestedFromDevice && isCompleted))
            {
                bytesWrote += SerializeTransferBuffer(pCVOCR->TransferBufferLength,
                                                pCVOCR->TransferBuffer, pCVOCR->TransferBufferMDL);
            }
    
            bytesWrote += buffer.Write(&pCVOCR->RequestTypeReservedBits, sizeof(pCVOCR->RequestTypeReservedBits));

            bytesWrote += buffer.Write(&pCVOCR->Request, sizeof(pCVOCR->Request));
            bytesWrote += buffer.Write(&pCVOCR->Value,   sizeof(pCVOCR->Value));
            bytesWrote += buffer.Write(&pCVOCR->Index,   sizeof(pCVOCR->Index));
        }
        break;
        
    case URB_FUNCTION_GET_CONFIGURATION:
        {
            _URB_CONTROL_GET_CONFIGURATION_REQUEST *pCGCR = (_URB_CONTROL_GET_CONFIGURATION_REQUEST *) pUrb;

            buffer.SetBuffer(pBuffer, bufferSize);
            bytesWrote += buffer.Write((UCHAR)PACK_URB_CONTROL_GET_CONFIGURATION_REQUEST);
            bytesWrote += SerializeUrbHeader(&pCGCR->Hdr);
            bytesWrote += buffer.Write(isCompleted);

			if (isCompleted)
			{
				bytesWrote += SerializeTransferBuffer(pCGCR->TransferBufferLength,
                                        pCGCR->TransferBuffer, pCGCR->TransferBufferMDL);
			}
        }
        break;
        
    case URB_FUNCTION_GET_INTERFACE:
        {
            _URB_CONTROL_GET_INTERFACE_REQUEST *pCGIR = (_URB_CONTROL_GET_INTERFACE_REQUEST *) pUrb;

            buffer.SetBuffer(pBuffer, bufferSize);
            bytesWrote += buffer.Write((UCHAR)PACK_URB_CONTROL_GET_INTERFACE_REQUEST);
            bytesWrote += SerializeUrbHeader(&pCGIR->Hdr);
            bytesWrote += buffer.Write(isCompleted);

			if (isCompleted)
			{
				bytesWrote += SerializeTransferBuffer(pCGIR->TransferBufferLength,
                                            pCGIR->TransferBuffer, pCGIR->TransferBufferMDL);
			}
            
            bytesWrote += buffer.Write(&pCGIR->Interface, sizeof(pCGIR->Interface));
        }
        break;
#if (_WIN32_WINNT >= 0x0501)		
    case URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR:
        {
            _URB_OS_FEATURE_DESCRIPTOR_REQUEST *pOFDR = (_URB_OS_FEATURE_DESCRIPTOR_REQUEST *) pUrb;

            buffer.SetBuffer(pBuffer, bufferSize);
            bytesWrote += buffer.Write((UCHAR)PACK_URB_OS_FEATURE_DESCRIPTOR_REQUEST);
            bytesWrote += SerializeUrbHeader(&pOFDR->Hdr);
            bytesWrote += buffer.Write(isCompleted);

			if (isCompleted)
			{
				bytesWrote += SerializeTransferBuffer(pOFDR->TransferBufferLength,
                                        pOFDR->TransferBuffer, pOFDR->TransferBufferMDL);
            }
			
            UCHAR Recipient = pOFDR->Recipient; // bit field in _URB_OS_FEATURE_DESCRIPTOR_REQUEST structure
            bytesWrote += buffer.Write(&Recipient, sizeof(Recipient));

            bytesWrote += buffer.Write(&pOFDR->InterfaceNumber,           sizeof(pOFDR->InterfaceNumber));
            bytesWrote += buffer.Write(&pOFDR->MS_PageIndex,              sizeof(pOFDR->MS_PageIndex));
            bytesWrote += buffer.Write(&pOFDR->MS_FeatureDescriptorIndex, sizeof(pOFDR->MS_FeatureDescriptorIndex));
        }
        break;
#endif
    default:
        KdPrint(("URBSerializer::SerializeURB(...): Unknown UrbHeader.Function code 0x%x\n",
                    pUrb->UrbHeader.Function));
        break;
    } // End of switch
    return bytesWrote;
}
